﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fiveesoft.Utility
{
    public class DateTimeTimeZone
    {
        private  DateTime _utcDateTime;
        private  TimeZoneInfo _localTimeZone;

        public DateTimeTimeZone(){}

        public DateTimeTimeZone(DateTime serverDateTime, TimeZoneData localTimeZone)
        {
            this._localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(localTimeZone.ID);
            DateTime inputDT = new DateTime(serverDateTime.Year, serverDateTime.Month, serverDateTime.Day, serverDateTime.Hour, serverDateTime.Minute, serverDateTime.Second);
            _utcDateTime = TimeZoneInfo.ConvertTimeToUtc(inputDT, _localTimeZone);
        }

        public static DateTime Now(TimeZoneEnum timeZone)
        {
            TimeZoneData tzData = TimeZones.GetTimeZoneData(timeZone);
            TimeZoneInfo timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzData.ID);

            DateTime utcTime = DateTime.UtcNow;
            return TimeZoneInfo.ConvertTimeFromUtc(utcTime, timezoneInfo);
        }

        public DateTime UTCTime { get { return _utcDateTime; } set { _utcDateTime = value; } }

        public TimeZoneInfo TimeZone { get { return _localTimeZone; } set { _localTimeZone = value; } }

        public DateTime LocalTime
        {
            get { return TimeZoneInfo.ConvertTime(_utcDateTime, _localTimeZone); }
        }

        public static DateTimeTimeZone LoadUTCTime(DateTime utcTime, TimeZoneData localTimeZone)
        {
            DateTimeTimeZone dateTime = new DateTimeTimeZone();
            dateTime.UTCTime = utcTime;
            dateTime.TimeZone = TimeZoneInfo.FindSystemTimeZoneById(localTimeZone.ID);
            return dateTime;
        }

        public static DateTimeTimeZone LoadUTCTime(DateTime utcTime, TimeZoneEnum localTimeZone)
        {
            DateTimeTimeZone dateTime = new DateTimeTimeZone();
            dateTime.UTCTime = utcTime;
            TimeZoneData data = TimeZones.GetTimeZoneData(localTimeZone);
            dateTime.TimeZone = TimeZoneInfo.FindSystemTimeZoneById(data.ID);
            return dateTime;
        }
    }

    public enum TimeZoneEnum
    {
        Kabul0430E,
        Alaska0900E,
        KuwaitRiyadh0300E,
        AbuDhabiMuscat0400E,
        Baghdad0300E,
        BuenosAires0300W,
        AtlanticTime0400W,
        Darwin0930E,
        CanberraMelbourneSydney1000E,
        Baku0400E,
        Azores0100W, 
        Saskatchewan0600W,
        Adelaide0930E,
        CentralAmerica0600W,
        BelgradeBratislavaBudapestLjubljanaPrague0100E,
        SarajevoSkopjeWarsawZagreb0100E,
        CentralTimeUSCanada0600W,
        BeijingChongqingHongKongUrumqi0800E,
        Brisbane1000E,
        DublinEdinburghLisbonLondon0000,
        Greenland0300W,
        MonroviaReykjavik0000,
        Hawaii1000W,
        AucklandWellington1200E,
        Santiago0400W,
        PacificTime0800W,
        UTC,
        Perth0800E
    }

    public class TimeZones
    {
        public static IEnumerable<TimeZoneData> AllTimeZones()
        {
            List<TimeZoneData> timeZones = new List<TimeZoneData>();
            timeZones.Add(new TimeZoneData() { ID = "Afghanistan Standard Time",  TimeZoneCountries = "(UTC+04:30) Kabul", Offset = 4.5, EnumKey = "Kabul0430",});
            timeZones.Add(new TimeZoneData() { ID = "Alaskan Standard Time", TimeZoneCountries = "(UTC-09:00) Alaska", Offset = -9, EnumKey = "Alaska0900" });
            timeZones.Add(new TimeZoneData() { ID = "Arab Standard Time", TimeZoneCountries = "(UTC+03:00) Kuwait, Riyadh", Offset = 3, EnumKey = "KuwaitRiyadh0300" });
            timeZones.Add(new TimeZoneData() { ID = "Arabian Standard Time", TimeZoneCountries = "(UTC+04:00) Abu Dhabi, Muscat", Offset = 4, EnumKey = "AbuDhabiMuscat0400" });
            timeZones.Add(new TimeZoneData() { ID = "Arabic Standard Time", TimeZoneCountries = "(UTC+03:00) Baghdad", Offset = 3, EnumKey = "Baghdad0300" });
            timeZones.Add(new TimeZoneData() { ID = "Argentina Standard Time", TimeZoneCountries = "(UTC-03:00) Buenos Aires", Offset = -3, EnumKey = "BuenosAires0300W" });
            timeZones.Add(new TimeZoneData() { ID = "Atlantic Standard Time", TimeZoneCountries = "(UTC-04:00) Atlantic Time (Canada)", Offset = -4, EnumKey = "AtlanticTime0400W" });
            timeZones.Add(new TimeZoneData() { ID = "AUS Central Standard Time", TimeZoneCountries = "(UTC+09:30) Darwin", Offset = 9.5, EnumKey = "Darwin0930E" });
            timeZones.Add(new TimeZoneData() { ID = "AUS Eastern Standard Time", TimeZoneCountries = "(UTC+10:00) Canberra, Melbourne, Sydney", Offset = 10, EnumKey = "CanberraMelbourneSydney1000E" });
            timeZones.Add(new TimeZoneData() { ID = "Azerbaijan Standard Time", TimeZoneCountries = "(UTC+04:00) Baku", Offset = 4, EnumKey = "Baku0400E" });
            timeZones.Add(new TimeZoneData() { ID = "Azores Standard Time", TimeZoneCountries = "(UTC-01:00) Azores", Offset = -1, EnumKey = "Azores0100W" });
            timeZones.Add(new TimeZoneData() { ID = "Canada Central Standard Time", TimeZoneCountries = "(UTC-06:00) Saskatchewan", Offset = -6, EnumKey = "Saskatchewan0600W" });
            timeZones.Add(new TimeZoneData() { ID = "Cape Verde Standard Time", TimeZoneCountries = "(UTC-01:00) Cape Verde Is.", Offset = -1 });
            timeZones.Add(new TimeZoneData() { ID = "Caucasus Standard Time", TimeZoneCountries = "(UTC+04:00) Yerevan", Offset = 4 });
            timeZones.Add(new TimeZoneData() { ID = "Cen. Australia Standard Time", TimeZoneCountries = "(UTC+09:30) Adelaide", Offset = 9.5, EnumKey = "Adelaide0930E" });
            timeZones.Add(new TimeZoneData() { ID = "Central America Standard Time", TimeZoneCountries = "(UTC-06:00) Central America", Offset = -6, EnumKey = "CentralAmerica0600W" });
            timeZones.Add(new TimeZoneData() { ID = "Central Asia Standard Time", TimeZoneCountries = "(UTC+06:00) Astana, Dhaka", Offset = 6 });
            timeZones.Add(new TimeZoneData() { ID = "Central Brazilian Standard Time", TimeZoneCountries = "(UTC-04:00) Manaus", Offset = -4 });
            timeZones.Add(new TimeZoneData() { ID = "Central Europe Standard Time", TimeZoneCountries = "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", Offset = 1, EnumKey = "BelgradeBratislavaBudapestLjubljanaPrague0100E" });
            timeZones.Add(new TimeZoneData() { ID = "Central European Standard Time", TimeZoneCountries = "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", Offset = 1, EnumKey = "SarajevoSkopjeWarsawZagreb0100E" });
            timeZones.Add(new TimeZoneData() { ID = "Central Pacific Standard Time", TimeZoneCountries = "(UTC+11:00) Magadan, Solomon Is., New Caledonia", Offset = 11 });
            timeZones.Add(new TimeZoneData() { ID = "Central Standard Time", TimeZoneCountries = "(UTC-06:00) Central Time (US & Canada)", Offset = -6, EnumKey = "CentralTimeUSCanada0600W" });
            timeZones.Add(new TimeZoneData() { ID = "Central Standard Time (Mexico)", TimeZoneCountries = "(UTC-06:00) Guadalajara, Mexico City, Monterrey", Offset = -6 });
            timeZones.Add(new TimeZoneData() { ID = "China Standard Time", TimeZoneCountries = "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", Offset = 8, EnumKey = "BeijingChongqingHongKongUrumqi0800E" });
            timeZones.Add(new TimeZoneData() { ID = "Dateline Standard Time", TimeZoneCountries = "(UTC-12:00) International Date Line West", Offset = -12 });
            timeZones.Add(new TimeZoneData() { ID = "E. Africa Standard Time", TimeZoneCountries = "(UTC+03:00) Nairobi", Offset = 3 });
            timeZones.Add(new TimeZoneData() { ID = "E. Australia Standard Time", TimeZoneCountries = "(UTC+10:00) Brisbane", Offset = 10, EnumKey = "Brisbane1000E" });
            timeZones.Add(new TimeZoneData() { ID = "E. Europe Standard Time", TimeZoneCountries = "(UTC+02:00) Minsk", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "E. South America Standard Time", TimeZoneCountries = "(UTC-03:00) Brasilia", Offset = 3 });
            timeZones.Add(new TimeZoneData() { ID = "Eastern Standard Time", TimeZoneCountries = "(UTC-05:00) Eastern Time (US & Canada)", Offset = -5 });
            timeZones.Add(new TimeZoneData() { ID = "Egypt Standard Time", TimeZoneCountries = "(UTC+02:00) Cairo", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Ekaterinburg Standard Time", TimeZoneCountries = "(UTC+05:00) Ekaterinburg", Offset = 5 });
            timeZones.Add(new TimeZoneData() { ID = "Fiji Standard Time", TimeZoneCountries = "(UTC+12:00) Fiji, Marshall Is.", Offset = 12 });
            timeZones.Add(new TimeZoneData() { ID = "FLE Standard Time", TimeZoneCountries = "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Georgian Standard Time", TimeZoneCountries = "(UTC+03:00) Tbilisi", Offset = 3 });
            timeZones.Add(new TimeZoneData() { ID = "GMT Standard Time", TimeZoneCountries = "(UTC) Dublin, Edinburgh, Lisbon, London", Offset = 0, EnumKey = "DublinEdinburghLisbonLondon0000" });
            timeZones.Add(new TimeZoneData() { ID = "Greenland Standard Time", TimeZoneCountries = "(UTC-03:00) Greenland", Offset = -3, EnumKey = "Greenland0300W" });
            timeZones.Add(new TimeZoneData() { ID = "Greenwich Standard Time", TimeZoneCountries = "(UTC) Monrovia, Reykjavik", Offset = 0, EnumKey = "MonroviaReykjavik0000" });
            timeZones.Add(new TimeZoneData() { ID = "GTB Standard Time", TimeZoneCountries = "(UTC+02:00) Athens, Bucharest, Istanbul", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Hawaiian Standard Time", TimeZoneCountries = "(UTC-10:00) Hawaii", Offset = -10, EnumKey = "Hawaii1000W" });
            timeZones.Add(new TimeZoneData() { ID = "India Standard Time", TimeZoneCountries = "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", Offset = 5.5 });
            timeZones.Add(new TimeZoneData() { ID = "Iran Standard Time", TimeZoneCountries = "(UTC+03:30) Tehran", Offset = 3.5 });
            timeZones.Add(new TimeZoneData() { ID = "Israel Standard Time", TimeZoneCountries = "(UTC+02:00) Jerusalem", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Jordan Standard Time", TimeZoneCountries = "(UTC+02:00) Amman", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Kamchatka Standard Time", TimeZoneCountries = "(UTC+12:00) Petropavlovsk-Kamchatsky", Offset = 12 });
            timeZones.Add(new TimeZoneData() { ID = "Korea Standard Time", TimeZoneCountries = "(UTC+09:00) Seoul", Offset = 9 });
            timeZones.Add(new TimeZoneData() { ID = "Mauritius Standard Time", TimeZoneCountries = "(UTC+04:00) Port Louis", Offset = 4 });
            timeZones.Add(new TimeZoneData() { ID = "Mid-Atlantic Standard Time", TimeZoneCountries = "(UTC-02:00) Mid-Atlantic", Offset = -2 });
            timeZones.Add(new TimeZoneData() { ID = "Middle East Standard Time", TimeZoneCountries = "(UTC+02:00) Beirut", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Montevideo Standard Time", TimeZoneCountries = "(UTC-03:00) Montevideo", Offset = -3 });
            timeZones.Add(new TimeZoneData() { ID = "Morocco Standard Time", TimeZoneCountries = "(UTC) Casablanca", Offset = 0 });
            timeZones.Add(new TimeZoneData() { ID = "Mountain Standard Time", TimeZoneCountries = "(UTC-07:00) Mountain Time (US & Canada)", Offset = -7 });
            timeZones.Add(new TimeZoneData() { ID = "Mountain Standard Time (Mexico)", TimeZoneCountries = "(UTC-07:00) Chihuahua, La Paz, Mazatlan", Offset = -7 });
            timeZones.Add(new TimeZoneData() { ID = "Myanmar Standard Time", TimeZoneCountries = "(UTC+06:30) Yangon (Rangoon)", Offset = 6.5 });
            timeZones.Add(new TimeZoneData() { ID = "N. Central Asia Standard Time", TimeZoneCountries = "(UTC+06:00) Almaty, Novosibirsk", Offset = 6 });
            timeZones.Add(new TimeZoneData() { ID = "Namibia Standard Time", TimeZoneCountries = "(UTC+02:00) Windhoek", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Nepal Standard Time", TimeZoneCountries = "(UTC+05:45) Kathmandu", Offset = 5.75 });
            timeZones.Add(new TimeZoneData() { ID = "New Zealand Standard Time", TimeZoneCountries = "(UTC+12:00) Auckland, Wellington", Offset = 12, EnumKey = "AucklandWellington1200E" });
            timeZones.Add(new TimeZoneData() { ID = "Newfoundland Standard Time", TimeZoneCountries = "(UTC-03:30) Newfoundland", Offset = -3.5 });
            timeZones.Add(new TimeZoneData() { ID = "North Asia East Standard Time", TimeZoneCountries = "(UTC+08:00) Irkutsk, Ulaan Bataar", Offset = 8 });
            timeZones.Add(new TimeZoneData() { ID = "North Asia Standard Time", TimeZoneCountries = "(UTC+07:00) Krasnoyarsk", Offset = 7 });
            timeZones.Add(new TimeZoneData() { ID = "Pacific SA Standard Time", TimeZoneCountries = "(UTC-04:00) Santiago", Offset = -4, EnumKey = "Santiago0400W" });
            timeZones.Add(new TimeZoneData() { ID = "Pacific Standard Time", TimeZoneCountries = "(UTC-08:00) Pacific Time (US & Canada)", Offset = -8, EnumKey = "PacificTime0800W" });
            timeZones.Add(new TimeZoneData() { ID = "Pacific Standard Time (Mexico)", TimeZoneCountries = "(UTC-08:00) Tijuana, Baja California", Offset = -8 });
            timeZones.Add(new TimeZoneData() { ID = "Pakistan Standard Time", TimeZoneCountries = "(UTC+05:00) Islamabad, Karachi", Offset = 5 });
            timeZones.Add(new TimeZoneData() { ID = "Paraguay Standard Time", TimeZoneCountries = "(UTC-04:00) Asuncion", Offset = -4 });
            timeZones.Add(new TimeZoneData() { ID = "Romance Standard Time", TimeZoneCountries = "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", Offset = 1 });
            timeZones.Add(new TimeZoneData() { ID = "Russian Standard Time", TimeZoneCountries = "(UTC+03:00) Moscow, St. Petersburg, Volgograd", Offset = 3 });
            timeZones.Add(new TimeZoneData() { ID = "SA Eastern Standard Time", TimeZoneCountries = "(UTC-03:00) Cayenne", Offset = -3 });
            timeZones.Add(new TimeZoneData() { ID = "SA Pacific Standard Time", TimeZoneCountries = "(UTC-05:00) Bogota, Lima, Quito", Offset = -5 });
            timeZones.Add(new TimeZoneData() { ID = "SA Western Standard Time", TimeZoneCountries = "(UTC-04:00) Georgetown, La Paz, San Juan", Offset = -4 });
            timeZones.Add(new TimeZoneData() { ID = "Samoa Standard Time", TimeZoneCountries = "(UTC-11:00) Midway Island, Samoa", Offset = -11 });
            timeZones.Add(new TimeZoneData() { ID = "SE Asia Standard Time", TimeZoneCountries = "(UTC+07:00) Bangkok, Hanoi, Jakarta", Offset = 7 });
            timeZones.Add(new TimeZoneData() { ID = "Singapore Standard Time", TimeZoneCountries = "(UTC+08:00) Kuala Lumpur, Singapore", Offset = 8 });
            timeZones.Add(new TimeZoneData() { ID = "South Africa Standard Time", TimeZoneCountries = "(UTC+02:00) Harare, Pretoria", Offset = 2 });
            timeZones.Add(new TimeZoneData() { ID = "Sri Lanka Standard Time", TimeZoneCountries = "(UTC+05:30) Sri Jayawardenepura", Offset = 5.5 });
            timeZones.Add(new TimeZoneData() { ID = "Taipei Standard Time", TimeZoneCountries = "(UTC+08:00) Taipei", Offset = 8 });
            timeZones.Add(new TimeZoneData() { ID = "Tasmania Standard Time", TimeZoneCountries = "(UTC+10:00) Hobart", Offset = 10 });
            timeZones.Add(new TimeZoneData() { ID = "Tokyo Standard Time", TimeZoneCountries = "(UTC+09:00) Osaka, Sapporo, Tokyo", Offset = 9 });
            timeZones.Add(new TimeZoneData() { ID = "Tonga Standard Time", TimeZoneCountries = "(UTC+13:00) Nuku'alofa", Offset = 13 });
            timeZones.Add(new TimeZoneData() { ID = "US Eastern Standard Time", TimeZoneCountries = "(UTC-05:00) Indiana (East)", Offset = -5 });
            timeZones.Add(new TimeZoneData() { ID = "US Mountain Standard Time", TimeZoneCountries = "(UTC-07:00) Arizona", Offset = -7 });
            timeZones.Add(new TimeZoneData() { ID = "UTC", TimeZoneCountries = "(UTC) Coordinated Universal Time", Offset = 0, EnumKey = "UTC"});
            timeZones.Add(new TimeZoneData() { ID = "Venezuela Standard Time", TimeZoneCountries = "(UTC-04:30) Caracas", Offset = -4.5 });
            timeZones.Add(new TimeZoneData() { ID = "Vladivostok Standard Time", TimeZoneCountries = "(UTC+10:00) Vladivostok", Offset = 10 });
            timeZones.Add(new TimeZoneData() { ID = "W. Australia Standard Time", TimeZoneCountries = "(UTC+08:00) Perth", Offset = 8, EnumKey = "Perth0800E" });
            timeZones.Add(new TimeZoneData() { ID = "W. Central Africa Standard Time", TimeZoneCountries = "(UTC+01:00) West Central Africa", Offset = 1 });
            timeZones.Add(new TimeZoneData() { ID = "W. Europe Standard Time", TimeZoneCountries = "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", Offset = 1 });
            timeZones.Add(new TimeZoneData() { ID = "West Asia Standard Time", TimeZoneCountries = "(UTC+05:00) Tashkent", Offset = 5 });
            timeZones.Add(new TimeZoneData() { ID = "West Pacific Standard Time", TimeZoneCountries = "(UTC+10:00) Guam, Port Moresby", Offset = 10 });
            timeZones.Add(new TimeZoneData() { ID = "Yakutsk Standard Time", TimeZoneCountries = "(UTC+09:00) Yakutsk", Offset = 9 });

            return timeZones;
        }

        public static TimeZoneData GetTimeZoneData(TimeZoneEnum eTimeZoneEnum)
        {
            string key = eTimeZoneEnum.ToString();
            return AllTimeZones().First(t => t.EnumKey == key);
        }
    }

    public class TimeZoneData
    {
        public string ID { get; set; }
        public string TimeZoneCountries { get; set; }
        public double Offset { get; set; }
        public string EnumKey { get; set; }
    }
}
